package ui.flowManager.expirimentProperties;

import java.util.ArrayList;

import ui.flowManager.MissingData;

/**
 * @author vladimir && alon
 *
 *	The Class designed to hold all the data of the 
 *	experiment that the user enter
 */
public class ExperimentProperties {
	//Data
	private int 							numOfGames = 0;
	private ArrayList<GameRepresentation> 	gamesList  = null;
	private static String					experimentName = null;
	
	
	/**
	 * @author vladimir && alon
	 * 
	 * Enum that describe what missing to set in the Experiment Properties
	 */
	 public enum Missing_Data_Error {
		   NO_MISSING_DATA, NO_GAMES, GAME_NOT_INITIALIZED, PLAYER_NOT_INITIALIZED
		   };
	 
	
	/**
	 * 	   
	 * @author vladimir
	 *  To which 
	 */
	 public enum Agent_Group{ STUDIED_AGENT, CONTROL_AGENT};

	/**
	 * @return
	 */
	//Geters && Seters
	public int getNumOfGames() {
		return numOfGames;
	}

	/**
	 * @param numOfGames
	 */
	
	public void setGames(int numOfGames) {
		this.numOfGames = numOfGames;
		gamesList = new ArrayList<GameRepresentation>();
		
		//add empty games to the game
		for(int i = 0; i < numOfGames; ++i )
		{
			gamesList.add(new GameRepresentation());
		}
		
	}
	
	/**
	 * Check if the game have players
	 * @param gameNumber
	 * @return is Have Players
	 */
	public boolean havePlayers(int gameNumber, Agent_Group group)
	{
		//case the game exist
		if ((gamesList != null)&&(gameNumber <= numOfGames))
		{
			//case have players
			if (gamesList.get(gameNumber - 1).getNumOfPlayers(group) > 0)
			{
				return true;
			}
			// the game have not players
			else return false;
		}
		
		// game not exist
		return false;
	}
	
	/**
	 * Check that the game number not exceed number of players in the game
	 * @param gameNumber
	 * @param playerNumber
	 * @return
	 */
	public boolean smallerOrEqualThanNumPlayers(int gameNumber, int playerNumber, Agent_Group group)
	{
		boolean smaller = false;
		
		//check that the player 
		if(playerNumber <= getGame(gameNumber).getNumOfPlayers(group))
		{
			smaller = true;
		}
		
		return smaller;
	}
	
	
	
	/**
	 * @param 	gameNum
	 * @param 	playerNum
	 * @return 	isInitialized
	 */
	public boolean isPlayerInitialized(int gameNum, int playerNum, Agent_Group group)
	{
		boolean isInitialized = false;
		
		GameRepresentation game = getGame(gameNum);
		//case there is a players in the game 
		if(game.getNumOfPlayers(group) > 0)
		{
			//the check if was initialized
			isInitialized = game.getPlayer(playerNum, group).isInitialized();	
		}
		
		return isInitialized;
	}
	
	/**
	 * Looking for the first thing that missing in the data
	 * @return missingData
	 */
	public MissingData whatMissing(Agent_Group group)
	{
		MissingData missingData = null;
		
		//case no games
		if (numOfGames == 0)
		{
			missingData = new MissingData(Missing_Data_Error.NO_GAMES);
		}
		else
		{
			GameRepresentation 	game = null;
			AgentRepresentation agent = null;
			boolean 			breakOut = false;
			//go over the games 
			for(int i = 0; i < numOfGames; ++i)
			{
				// in the list the counting start from zero
				game = gamesList.get(i);
				
				//case the game have not players
				if ((game.getNumOfPlayers(group) == 0) || (game.getNumOfTurns() == 0))
				{
					//create
					missingData = new MissingData(Missing_Data_Error.GAME_NOT_INITIALIZED);
					// add 1, because counting of i start from zero
					missingData.setGameNumber(i + 1);
					//get out from the loop
					break;		
				}
				
				//go over the players
				for (int j = 0; j < game.getNumOfPlayers(group); ++j)
				{
					// add 1 , because in getPlayer the counting is natural (start from 1)
					agent = game.getPlayer(j + 1, group);
					//case agent not initialized
					if (!agent.isInitialized())
					{
						//set the missing data
						missingData = new MissingData(Missing_Data_Error.PLAYER_NOT_INITIALIZED);
						missingData.setGameNumber(i + 1);
						missingData.setPlayerNumber(j + 1);
						
						//to break from outsider loop
						breakOut = true;
						break;
					}
				}
				//check if break the outer loop
				if (breakOut)
				{
					break;
				}
			}
			//end of the outer loop
		}
		
		//case no missing Data
		if(missingData == null){
			missingData = new MissingData(Missing_Data_Error.NO_MISSING_DATA);
		}
		
		return missingData;
	}
	
	/**
	 * 
	 * @param gameNumber
	 * @return number of players
	 */
	public int getNumOfPlayers(int gameNumber, Agent_Group group)
	{
		
		//case the game exist
		if ((gamesList != null)&&(gameNumber <= numOfGames))
			// "- 1" because the  game counting start from 1 
			return gamesList.get(gameNumber - 1).getNumOfPlayers(group);
	
		// game not exist
		return -1;
	}
	
	public int getNumOfTurns(int gameNumber)
	{
		//case the game exist
		if ((gamesList != null)&&(gameNumber <= numOfGames))
			return gamesList.get(gameNumber - 1).getNumOfTurns();
		// game not exist
		return -1;
	}
	
	public int getNumOfRepeats(int gameNumber)
	{
		if((gamesList != null) && (gameNumber <= numOfGames))
			return gamesList.get(gameNumber - 1).getNumOfRepeats();
		
		return -1;
	}
	
	public String getObservationType(int gameNumber)
	{
		//case the game exist
		if ((gamesList != null)&&(gameNumber <= numOfGames))
			// "- 1" because the  game counting start from 1 
			return gamesList.get(gameNumber - 1).getObservationType();
		
		// game not exist
		return null;
	}
	
	/**
	 * @param gameNumber
	 * @param numberOfTurns
	 * @param observation
	 */
	public void setGameData(int gameNumber ,int numberOfTurns, int numberOfRepeats ,String observation)
	{
		getGame(gameNumber).setGameData(numberOfTurns,numberOfRepeats,observation);
	}
	
	/**
	 * 
	 * @param gameNumber
	 * @param numberOfPlayers
	 * @param group
	 */
	public void setPlayers(int gameNumber, int numberOfPlayers, Agent_Group group)
	{
		//set the new parameters of the game
		getGame(gameNumber).setPlayers(numberOfPlayers, group);
	}
	
	
	/**
	 * Adding more players
	 * @param gameNumber
	 * @param numberOfPlayers
	 */
	public void addPlayers(int gameNumber, int numberOfPlayers, Agent_Group group)
	{
		//set the new parameters of the game
		getGame(gameNumber).addPlayers(numberOfPlayers, group);
	}
	
	/**
	 * return player without checking caces of existence
	 * @param 	gameNumber
	 * @param 	numberOfPlayers
	 * @return 	AgentRepresentation 
	 */
	
	public AgentRepresentation getPlayer(int gameNumber, int playerNumber, Agent_Group group)
	{
		return getGame(gameNumber).getPlayer(playerNumber, group);
	}

	
	/**
	 * Return GameRepresentation, starting from index 1 and return his Representation 
	 * @param gameNumber
	 * @return GameRepresentation
	 */
	public GameRepresentation getGame(int gameNumber)
	{
		return gamesList.get(gameNumber - 1);
	}
	
	
	/**
	 * Get a game Number and check if this game is initialized
	 * @param gameNumber
	 * @return isInitilized
	 */
	public boolean isInitialized(int gameNumber)
	{
		return getGame(gameNumber).isInitialized();
	}
	
	public AdditionalSettings getAdditionalSettings(int gameNumber, int playerNumber, Agent_Group group)
	{
		return getGame(gameNumber).getPlayer(playerNumber,group).getAdditionalSettings();
	}
	
	public void setAdditionalSettings(int gameNumber, int playerNumber, 
						AdditionalSettings additionalSettings,Agent_Group group)
	{
		getGame(gameNumber).getPlayer(playerNumber, group).setAdditionalSettings(additionalSettings);
	}

	public static String getExperimentName() {
		return experimentName;
	}

	public void setExperimentName(String experimentName) {
		this.experimentName = experimentName;
	}
}
